#!/usr/bin/env bash
set -euo pipefail
# This command can be run in two different ways.  If COSA_DIR is unset, it
# must be run from a coreos-assembler working directory.  It will takes new
# files from overrides/rootfs and applies them
# on top of a previously built qemu image.  It creates a new deployment.
# If COSA_DIR is set, it's assumed instead that you are developing on *one*
# project - it will take the output of `make && make install DESTDIR=` as
# an overlay on top of the build from COSA_DIR.  Notably, the qcow2 image
# will end up in the project's working directory - so you can effectively
# have independent CoreOS builds for each project.
# This model is likely preferable if you are developing on an individual
# project - you should turn to the main `cosa build/cosa build-fast` when
# working on multiple projects.

dn=$(dirname "$0")
# shellcheck source=src/cmdlib.sh
. "${dn}"/cmdlib.sh

print_help() {
    cat 1>&2 <<'EOF'
Usage: nestos-assembler build-fast [--undeploy]
EOF
}

# Parse options
NO_UNDEPLOY=0
rc=0
options=$(getopt --options h --longoptions help,no-undeploy -- "$@") || rc=$?
[ $rc -eq 0 ] || {
    print_help
    exit 1
}
eval set -- "$options"
while true; do
    case "$1" in
        -h | --help)
            print_help
            exit 0
            ;;
        --no-undeploy)
            NO_UNDEPLOY=1
            ;;
        --)
            shift
            break
            ;;
        -*)
            fatal "$0: unrecognized option: $1"
            ;;
        *)
            break
            ;;
    esac
    shift
done


# Detect the case that we're in a git repo without COSA_DIR
# Note we use -e and not -d here so it also works in git worktrees.
if test -e .git; then
    if test -z "${COSA_DIR}"; then
        # shellcheck disable=SC2016
        fatal 'This command requires inheriting from a previous full OS build.
Use e.g. `export COSA_DIR=/path/to/fcos` that has a previous
run of `nosa build`.'
    fi
    projectdir=$(pwd)
    cd "${COSA_DIR}"
else
    # If it's not a git repo, assume it's a cosa dir
    unset COSA_DIR
    projectdir=
fi

prepare_build

previous_build=$(get_latest_build)
previous_qemu=
if [ -z "${previous_build}" ]; then
    fatal "previous build required for a fast build"
fi
previous_builddir=$(get_build_dir "${previous_build}")
previous_commit=$(jq -r '.["ostree-commit"]' < "${previous_builddir}/meta.json")
previous_qemu=$(jq -r '.["images"]["qemu"]["path"]' < "${previous_builddir}/meta.json")
if [ "${previous_qemu}" = "null" ]; then
    fatal "--shortcut requires a previous build with qemu"
fi
echo "Basing on previous build: ${previous_build:-none}"

if [ -n "${projectdir}" ]; then
    cd "${projectdir}"
    instroot=_install
    # Rust projects will already have a handy directory for build artifacts
    if test -d target; then
        instroot=target/cosa-build-fast
    fi
    instroot=$(pwd)/${instroot}  # Must be absolute for `make`
    rm "${instroot}" -rf
    make
    make install DESTDIR="${instroot}"
    fastref=cosa/fastbuild/"$(basename "${projectdir}")"
    version="$(git describe --tags --abbrev=10)"
    if ! git diff --quiet; then
        version="${version}+dirty"
    fi
    outdir=${projectdir}/.cosa
    rootfsoverrides="${instroot}"
else
    fastref=cosa/fastbuild/${name}
    version="$(date +"%s")"
    outdir="${workdir}/tmp"
    rootfsoverrides="${workdir}/overrides/rootfs"
fi
if test "$(find "${rootfsoverrides}" -maxdepth 1 | wc -l)" == 0; then
    fatal "No rootfs overrides found"
fi
mkdir -p "${outdir}"

etcdir="${rootfsoverrides}/etc"
usretcdir="${rootfsoverrides}/usr/etc"
etcmoved=0
# FIXME add `ostree commit --rename=etc,usr/etc`
if [ -d "${etcdir}" ]; then
    mv -nT "${etcdir}" "${usretcdir}"
    etcmoved=1
fi
restore_etc() {
    if [ "${etcmoved}" = 1 ]; then
        mv -nT "${usretcdir}" "${etcdir}"
    fi
}
set -x
commit_args=()
if [ -n "${projectdir}" ]; then
    commit_args+=('--consume')  # nom nom nom
fi
# Depends https://github.com/ostreedev/ostree/pull/2041/commits/b3bbbd154225e81980546b2c0b5ed98714830696
if ! ostree --repo="${tmprepo}" commit -b "${fastref}" --base="${previous_commit}" --tree=dir="${rootfsoverrides}" \
    --owner-uid 0 --owner-gid 0 --selinux-policy-from-base --link-checkout-speedup --no-bindings --no-xattrs \
    --add-metadata-string=version="${version}" --parent="${previous_commit}" --keep-metadata='coreos-assembler.basearch' \
    --keep-metadata='nestos.stream' --keep-metadata='ostree.bootable' --fsync=0 "${commit_args[@]}"; then
    restore_etc
    exit 1
fi
set +x
commit=$(ostree --repo="${tmprepo}" rev-parse "${fastref}")
if [ -z "${projectdir}" ]; then
    restore_etc
fi
imgname="$(basename "${fastref}")-${version}-qemu.qcow2"
# Prune previous images
rm -vf "${outdir}"/*.qcow2
qemu-img create -f qcow2 -o backing_fmt=qcow2,backing_file="${previous_builddir}/${previous_qemu}" "${imgname}.tmp" 20G
RUNVM_NONET=1 runvm -drive if=virtio,id=target,format=qcow2,file="${imgname}.tmp",cache=unsafe -- \
    /usr/lib/coreos-assembler/offline-update-impl "${workdir}/tmp/repo" "${commit}" "${NO_UNDEPLOY}"
mv "${imgname}.tmp" "${imgname}"
mv "${imgname}" "${outdir}/${imgname}"
rm "${tmp_builddir}" -rf
echo "Created: ${outdir}/${imgname}"
